home *** CD-ROM | disk | FTP | other *** search
- /*************************************************************************************************
- *
- *
- * ObjectMacZapp -- a standard Mac OOP application template
- *
- *
- *
- * ZScroller.cpp -- a window with scrollbars
- *
- *
- *
- *
- *
- * © 1996, Graham Cox
- *
- *
- *
- *
- *************************************************************************************************/
-
-
- #include "ZScroller.h"
- #include "MacZoop.h"
-
-
- static pascal void ScrollBarZProc( ControlHandle theControl, short partCode );
- static pascal void ThumbZProc();
-
- static ControlActionUPP gScrollbarProc = NewControlActionProc( ScrollBarZProc );
- static ThumbActionUPP gThumbProc = NewThumbActionProc( ThumbZProc );
- static ControlHandle gCurrentScrollbar = NULL;
-
- /*--------------------------------*** CONSTRUCTOR ***---------------------------------*/
-
- ZScroller::ZScroller( ZCommander* aBoss,
- const short windID,
- const Boolean hasHScroll,
- const Boolean hasVScroll )
- : ZDragDropWindow( aBoss, windID )
- {
- theHBar = NULL;
- theVBar = NULL;
- SetRect( &bounds, 0, 0, 0, 0 );
- hScale = 1;
- vScale = 1;
-
- hasHBar = hasHScroll;
- hasVBar = hasVScroll;
-
- cInitValue = 0;
- }
-
-
- /*--------------------------------*** INITZWINDOW ***---------------------------------*/
- /*
-
- overrides the base ZWindow to initialise the scrollbars as well
-
- ----------------------------------------------------------------------------------------*/
-
- void ZScroller::InitZWindow()
- {
- inherited::InitZWindow(); // do the basic initialisation
-
- MakeScrollbars(); // make the scrollbar controls
- }
-
-
-
- /*----------------------------------*** ACTIVATE ***----------------------------------*/
- /*
-
- overrides ZWindow to show the scrollbars when the window state changes
-
- ----------------------------------------------------------------------------------------*/
-
- void ZScroller::Activate()
- {
- inherited::Activate();
-
- if ( hasVBar )
- ShowControl( theVBar );
-
- if ( hasHBar )
- ShowControl( theHBar );
- }
-
-
- /*---------------------------------*** DEACTIVATE ***---------------------------------*/
- /*
-
- overrides ZWindow to hide the scrollbars when the window state changes
-
- ----------------------------------------------------------------------------------------*/
-
-
- void ZScroller::Deactivate()
- {
- if ( hasVBar )
- HideControl( theVBar );
-
- if ( hasHBar )
- HideControl( theHBar );
-
- inherited::Deactivate();
- }
-
-
-
- /*------------------------------------*** DRAW ***------------------------------------*/
- /*
-
- overrides ZWindow to draw the content allowing for the scroll and the scrollbars themselves
-
- ----------------------------------------------------------------------------------------*/
-
- void ZScroller::Draw()
- {
- // need to set the origin to the scroll position here
-
- Rect content;
- short fH, fV;
-
- GetContentRect( &content );
- SetOriginToScroll();
-
- GetPosition( &fH, &fV );
- OffsetRect( &content, fH, fV );
- ClipRect( &content );
-
- DrawContent();
-
- SetOrigin( 0, 0 );
- ClipRect( &macWindow->portRect );
- UpdateControls( macWindow, macWindow->visRgn );
-
- DrawGrow();
- }
-
-
- /*----------------------------------*** DRAWGROW ***----------------------------------*/
- /*
-
- overrides ZWindow to draw the grow box, allowing for the actual scrollbars present
-
- ----------------------------------------------------------------------------------------*/
-
-
- void ZScroller::DrawGrow()
- {
- // overrides the standard method to clip down to the growbox. This prevents
- // scrollbar lines being drawn when there are no scrollbars in one dimension
-
- Rect growBoxRect = macWindow->portRect;
-
- if (! hasVBar )
- growBoxRect.top = growBoxRect.bottom - kStdScrollbarWidth;
-
- if (! hasHBar )
- growBoxRect.left = growBoxRect.right - kStdScrollbarWidth;
-
- ClipRect( &growBoxRect );
- DrawGrowIcon( macWindow );
- }
-
-
-
- /*------------------------------------*** CLICK ***-----------------------------------*/
- /*
-
- overrides ZWindow to handle clicks in the scrollbars and perform the scrolling
-
- ----------------------------------------------------------------------------------------*/
-
- void ZScroller::Click( const Point mouse, const short modifiers )
- {
- // handle a click in the content and also the scrollbar clicks
-
- short partCode,curValue;
- ControlHandle hitCtl;
- Point soMouse = mouse;
-
- // did the mouse go down in any part of a control (scrollbar)?
-
- partCode = FindControl( mouse, macWindow, &hitCtl );
-
- if ( partCode == kControlNoPart )
- {
- // translate the point to the current scroll offset
- // before passing it to ClickContent.
-
- if ( hasHBar )
- soMouse.h += GetControlValue( theHBar );
-
- if ( hasVBar )
- soMouse.v += GetControlValue( theVBar );
-
- ClickContent( soMouse, modifiers );
- }
- else
- {
- // scrollbar was hit, so track the control
-
- gCurrentScrollbar = hitCtl;
-
- curValue = GetControlValue( hitCtl );
-
- if ( partCode == kControlIndicatorPart )
- {
- #ifdef _LIVE_SCROLLING
- cInitValue = GetControlValue( hitCtl );
- partCode = TrackControl( hitCtl, mouse, gThumbProc );
- #else
- partCode = TrackControl( hitCtl, mouse, NULL );
- #endif
- }
- else
- partCode = TrackControl( hitCtl, mouse, gScrollbarProc );
-
- // if the thumb was dragged, figure out where it was dragged to and scroll
- // the contents appropriately
-
- if ( partCode == kControlIndicatorPart )
- {
- #ifndef _LIVE_SCROLLING
- curValue -= GetControlValue( hitCtl );
-
- if ( hitCtl == theHBar )
- Scroll( curValue, 0 );
- else
- Scroll( 0, curValue );
- #endif
-
- PostScroll( hitCtl );
- }
- gCurrentScrollbar = NULL;
- }
- }
-
-
- /*-------------------------------*** CLICKCONTENT ***---------------------------------*/
- /*
-
- You can override this to handle clicks in the content area of the window
-
- ----------------------------------------------------------------------------------------*/
-
-
- void ZScroller::ClickContent( const Point mouse, const short modifiers )
- {
- }
-
- /*-----------------------------------*** SETSIZE ***----------------------------------*/
- /*
-
- overrides ZWindow to reposition the scrollbars when the window size is changed
-
- ----------------------------------------------------------------------------------------*/
-
- void ZScroller::SetSize( const short width, const short height, const Boolean reDraw )
- {
- Focus();
-
- if ( hasVBar )
- HideControl( theVBar );
-
- if ( hasHBar )
- HideControl( theHBar );
-
- // need to erase the grow icon before sizing
-
- Rect growRect = macWindow->portRect;
-
- growRect.left = growRect.right - kStdScrollbarWidth;
- growRect.top = growRect.bottom - kStdScrollbarWidth;
- EraseRect( &growRect );
- InvalRect( &growRect );
-
- inherited::SetSize( width, height, reDraw );
-
- MoveScrollbars();
-
- if ( reDraw )
- Draw();
- }
-
-
-
- /*------------------------------------*** ZOOM ***------------------------------------*/
- /*
-
- overrides ZWindow to reposition the scrollbars when the window is zoomed
-
- ----------------------------------------------------------------------------------------*/
-
- void ZScroller::Zoom( const short partCode )
- {
- if ( hasVBar )
- HideControl( theVBar );
-
- if ( hasHBar )
- HideControl( theHBar );
-
- inherited::Zoom( partCode );
-
- MoveScrollbars();
- Draw();
- ValidRect( &macWindow->portRect );
- }
-
-
- /*----------------------------------*** SETBOUNDS ***---------------------------------*/
- /*
-
- sets the scrollable area to a certain size. This then recalculates the scrollbar settings
- so that that area can be scrolled over. The bounds is the "real" size of a document.
-
- ----------------------------------------------------------------------------------------*/
-
-
- void ZScroller::SetBounds( const Rect& aBounds)
- {
- bounds = aBounds;
- CalculateControlParams();
-
- // by default, set the sizeRect for the window to the bounds
- // plus the scrollbar widths
-
- Rect sz = aBounds;
-
- sz.top = sizeRect.top;
- sz.left = sizeRect.left;
-
- if ( hasHBar )
- sz.bottom += kStdScrollbarWidth;
-
- if ( hasVBar )
- sz.right += kStdScrollbarWidth;
-
- SetSizeRect( sz );
- }
-
-
-
- /*---------------------------------*** GETBOUNDS ***----------------------------------*/
- /*
-
- get the scrollable area
-
- ----------------------------------------------------------------------------------------*/
-
- void ZScroller::GetBounds( Rect* aBounds )
- {
- *aBounds = bounds;
- }
-
-
-
- /*------------------------------*** SETSCROLLAMOUNT ***-------------------------------*/
- /*
-
- sets how many pixels each click on a scroll arrow shifts the content area
-
- ----------------------------------------------------------------------------------------*/
-
- void ZScroller::SetScrollAmount( const short hAmount, const short vAmount )
- {
- hScale = hAmount;
- vScale = vAmount;
- }
-
-
- /*--------------------------------*** GETPOSITION ***---------------------------------*/
- /*
-
- returns the current scroll position of the window- i.e. the "frame" position relative to
- the "real" document area (the bounds)
-
- ----------------------------------------------------------------------------------------*/
-
-
- void ZScroller::GetPosition( short* hPosition, short* vPosition )
- {
- if ( hasVBar )
- *vPosition = GetControlValue( theVBar );
- else
- *vPosition = 0;
-
- if ( hasHBar )
- *hPosition = GetControlValue( theHBar );
- else
- *hPosition = 0;
- }
-
-
-
- /*----------------------------------*** SCROLLTO ***----------------------------------*/
- /*
-
- moves the content area to the scroll position passed. This immediately redraws the content
-
- ----------------------------------------------------------------------------------------*/
-
- void ZScroller::ScrollTo( const short hPosition, const short vPosition )
- {
- Focus();
-
- if ( hasHBar )
- SetControlValue( theHBar, hPosition );
-
- if ( hasVBar )
- SetControlValue( theVBar, vPosition );
-
- Draw();
- }
-
-
-
- /*-------------------------------*** GETCONTENTRECT ***-------------------------------*/
- /*
-
- get the scrollable portion of the window- the bit you can see, less the scrollbars.
-
- ----------------------------------------------------------------------------------------*/
-
- void ZScroller::GetContentRect( Rect* aRect )
- {
- // returns the scrollable part of the window. The bit without the scrollbars.
-
- *aRect = macWindow->portRect;
- if ( hasVBar )
- aRect->right -= kStdScrollbarWidth;
-
- if ( hasHBar )
- aRect->bottom -= kStdScrollbarWidth;
- }
-
-
-
- /*---------------------------*** CALCULATECONTROLPARAMS ***---------------------------*/
- /*
-
- sets the scrollbar maximums to correctly scroll the scrollarea. This is called when the
- bounds or the window frame area changes.
-
- ----------------------------------------------------------------------------------------*/
-
- void ZScroller::CalculateControlParams()
- {
- // this sets the maximums of the scrollbar to the difference between the content rect and
- // the bounds.
-
- Rect content;
- short hMax,vMax;
-
- GetContentRect( &content );
-
- hMax = ( bounds.right - bounds.left ) - ( content.right - content.left );
- vMax = ( bounds.bottom - bounds.top ) - ( content.bottom - content.top );
-
- if ( hMax < 0 )
- hMax = 0;
-
- if ( vMax < 0 )
- vMax = 0;
-
- if ( hasHBar )
- SetControlMaximum( theHBar, hMax );
-
- if ( hasVBar )
- SetControlMaximum( theVBar, vMax );
- }
-
-
-
- /*-------------------------------*** MAKESCROLLBARS ***-------------------------------*/
- /*
-
- creates the scrollbars as part of the initialisation
-
- ----------------------------------------------------------------------------------------*/
-
- void ZScroller::MakeScrollbars()
- {
- // create the scrollbar controls initially. This is done by calling NewControl. We
- // figure out the control rects from the window portrect.
-
- Rect barRect;
- Rect wPortRect;
-
- wPortRect = macWindow->portRect;
-
- if ( hasHBar )
- {
- barRect = wPortRect;
- barRect.right -= kStdScrollbarWidth - 1;
- barRect.top = barRect.bottom - kStdScrollbarWidth - 1;
- barRect.left -= 1;
- OffsetRect(&barRect,0,1);
-
- FailNIL( theHBar = NewControl( macWindow, &barRect, NULL, FALSE, 0, 0, 0, scrollBarProc, (long) this));
-
- SetControlReference( theHBar, (long) this );
- }
-
- if ( hasVBar )
- {
- barRect = wPortRect;
- barRect.bottom -= kStdScrollbarWidth - 1;
- barRect.left = barRect.right - kStdScrollbarWidth - 1;
- barRect.top -= 1;
- OffsetRect( &barRect, 1, 0 );
-
- FailNIL(theVBar = NewControl( macWindow, &barRect, NULL, FALSE, 0, 0, 0, scrollBarProc, (long) this));
-
- SetControlReference( theVBar, (long) this );
- }
- }
-
-
-
- /*-------------------------------*** MOVESCROLLBARS ***-------------------------------*/
- /*
-
- moves the scrollbars to the edges of the window. Called when the window frame size changes.
- The scrollbars should generally be hidden before this operation. This then reshows them if
- the window is active, and recomputes the max values. If the scroll position is forced to
- change as a result, this redraws the content in the correct position.
-
- ----------------------------------------------------------------------------------------*/
-
- void ZScroller::MoveScrollbars()
- {
- // move the scrollbars after the window size has changed. They should be hidden beforehand
- // and then shown afterwards. This will only show them if the window is active.
-
- Rect wPortRect;
- short w,h,hVal = 0,vVal = 0;
- Boolean isActive;
-
- wPortRect = macWindow->portRect;
- isActive = IsWindowHilited( macWindow ); // using Copland type macro
-
- if ( hasHBar )
- {
- hVal = GetControlValue( theHBar );
-
- w = wPortRect.right - wPortRect.left - kStdScrollbarWidth + 2;
- h = kStdScrollbarWidth + 1;
-
- SizeControl( theHBar, w, h );
- MoveControl( theHBar, wPortRect.left - 1, wPortRect.bottom - kStdScrollbarWidth );
-
- if ( isActive )
- ShowControl( theHBar );
-
- ValidRect(&(*theHBar)->contrlRect);
- }
-
- if ( hasVBar )
- {
- vVal = GetControlValue( theVBar );
-
- h = wPortRect.bottom - wPortRect.top - kStdScrollbarWidth + 2;
- w = kStdScrollbarWidth + 1;
-
- SizeControl(theVBar, w, h );
- MoveControl(theVBar, wPortRect.right - kStdScrollbarWidth, wPortRect.top - 1 );
-
- if ( isActive )
- ShowControl( theVBar );
-
- ValidRect(&(*theVBar)->contrlRect);
- }
-
- CalculateControlParams(); // recompute maximums
-
- if ( hasVBar )
- vVal -= GetControlValue( theVBar );
-
- if ( hasHBar )
- hVal -= GetControlValue( theHBar );
-
- // if the value of the control changed as a result of altering the maximum, we need to
- // ensure that the contents are scrolled to the right place.
-
- if ( hVal || vVal )
- {
- GetContentRect( &wPortRect );
- EraseRect( &wPortRect );
- }
- }
-
-
-
- /*---------------------------------*** POSTSCROLL ***---------------------------------*/
- /*
-
- You can override this if you are interested in getting called after the thumb of a
- scrollbar was dragged.
-
- ----------------------------------------------------------------------------------------*/
-
- void ZScroller::PostScroll( ControlHandle aCtl )
- {
- }
-
-
- /*------------------------------------*** SCROLL ***----------------------------------*/
- /*
-
- shifts the content by dH and dV, updating the revealed area. This is called by the scroll
- bar callback function to implement continous scrolling.
-
- ----------------------------------------------------------------------------------------*/
-
- void ZScroller::Scroll( const short dH, const short dV )
- {
- // scrolls the content rect. This calls scrollrect to move the majority of the
- // pixels, then calls DrawContent to fill in the rest.
-
- RgnHandle updateRgn,saveClip;
- Rect content;
- short fH,fV;
-
- GetContentRect( &content );
- updateRgn = NewRgn();
-
- GetClip( saveClip = NewRgn());
- ScrollRect( &content, dH, dV, updateRgn );
-
- // need to set the origin of the view to the new location
-
- SetOriginToScroll();
-
- // offset the update region to allow for the origin
-
- GetPosition( &fH, &fV );
- OffsetRgn( updateRgn, fH, fV );
- SetClip( updateRgn );
-
- // draw the update region
-
- DrawContent();
-
- // restore the zero origin
-
- SetOrigin( 0, 0 );
- SetClip( saveClip );
-
- DisposeRgn( saveClip );
- DisposeRgn( updateRgn );
- }
-
-
- /*-----------------------------*** SETORIGINTOSCROLL ***------------------------------*/
- /*
-
- sets the origin of the grafport to the correct scroll position. This is done to ensure
- that the contents get drawn in the right place regardless of where they are scrolled to.
-
- ----------------------------------------------------------------------------------------*/
-
- void ZScroller::SetOriginToScroll()
- {
- short vOrigin = 0;
- short hOrigin = 0;
-
- if ( hasVBar )
- vOrigin = GetControlValue( theVBar );
-
- if ( hasHBar )
- hOrigin = GetControlValue( theHBar );
-
- SetOrigin( hOrigin, vOrigin );
- }
-
-
- /*-------------------------------*** SCROLLHANDLER ***--------------------------------*/
- /*
-
- scrollbar callback function actually changes the scrollbar value as scrolling progresses
- and scrolls the content accordingly.
-
- ----------------------------------------------------------------------------------------*/
-
- void ZScroller::ScrollHandler( const ControlHandle aCtl, const short partCode )
- {
- // this actually peforms the scroll of the content rect
-
- short curValue,page;
- Boolean hitIsVertical;
- Rect content;
-
- curValue = GetControlValue( aCtl );
-
- // are we scrolling the horizontal or the vertical bar? Find out by comparing
- // the control with one of our data members
-
- hitIsVertical = ( aCtl == theVBar );
-
- // calculate the page amount. This is the height or width of the window less one
- // scale amount.
-
- GetContentRect( &content );
-
- if ( hitIsVertical )
- page = content.bottom - content.top - vScale;
- else
- page = content.right - content.left - hScale;
-
- switch ( partCode )
- {
- case kControlUpButtonPart:
- SetControlValue( aCtl, GetControlValue(aCtl) - (hitIsVertical? vScale : hScale ));
- break;
- case kControlDownButtonPart:
- SetControlValue( aCtl, GetControlValue(aCtl) + (hitIsVertical? vScale : hScale ));
- break;
- case kControlPageUpPart:
- SetControlValue( aCtl, GetControlValue(aCtl) - page );
- break;
- case kControlPageDownPart:
- SetControlValue( aCtl, GetControlValue(aCtl) + page );
- break;
- case kControlIndicatorPart:
- // called when live scrolling the thumb. Here we need to calculate where the mouse
- // is and figure out what the correct control value would be. If the mouse goes outside the
- // control too far, the control "springs back" to its previous value, stored in cInitValue.
- // we have to keep control here until the mouse is released otherwise the alterations to
- // the control value cause problems for the thumb dragging default behaviour if we allow
- // control back every time we are called. Yet another annoying toolbox anomaly...
-
- #ifdef _LIVE_SCROLLING
-
- Rect cr, slopR;
- long cRange, cVal;
- Point curMouse, lastMouse;
-
- GetMouse( &lastMouse );
-
- cr = (*aCtl)->contrlRect;
- slopR = cr;
- InsetRect( &slopR, -20, -20 );
-
- if ( hitIsVertical )
- {
- cr.top += kWidthOfScrollArrow;
- cr.bottom -= kWidthOfScrollArrow;
- }
- else
- {
- cr.left += kWidthOfScrollArrow;
- cr.right -= kWidthOfScrollArrow;
- }
-
- cRange = GetControlMaximum( aCtl ) - GetControlMinimum( aCtl );
-
- while ( StillDown())
- {
- GetMouse( &curMouse );
-
- if ( DeltaPoint( curMouse, lastMouse ))
- {
- lastMouse = curMouse;
-
- // calculate value based on mouse location
-
- if ( PtInRect( curMouse, &slopR ))
- {
- if ( hitIsVertical )
- cVal = ((long)( curMouse.v - cr.top ) * cRange ) / (long)( cr.bottom - cr.top );
- else
- cVal = ((long)( curMouse.h - cr.left ) * cRange ) / (long)( cr.right - cr.left );
-
- SetControlValue( aCtl, cVal );
- }
- else
- SetControlValue( aCtl, cInitValue ); // "spring" back...
-
- curValue -= GetControlValue( aCtl );
-
- if ( hitIsVertical )
- Scroll( 0, curValue );
- else
- Scroll( curValue, 0 );
-
- curValue = GetControlValue( aCtl );
- }
- }
-
- // the control manager will attempt to draw the thumb at this point. We'd rather it didn't
- // since we've already moved it. Thus we empty the clip region. A hack, but it works...
-
- SetRect( &cr, 0, 0, 0, 0 );
- ClipRect( &cr );
-
- #endif
- break;
- }
-
- if ( partCode != kControlIndicatorPart )
- {
- curValue -= GetControlValue( aCtl );
-
- if ( hitIsVertical )
- Scroll( 0, curValue );
- else
- Scroll( curValue, 0 );
- }
- }
-
-
-
-
- #pragma mark -
-
-
-
- static pascal void ScrollBarZProc( ControlHandle theControl, short partCode )
- {
- // action proc for passing scrolling callbacks back to the object.
-
- ZScroller* aScroller = (ZScroller*) GetControlReference( theControl );
-
- if ( aScroller )
- aScroller->ScrollHandler( theControl, partCode );
- }
-
-
-
- static pascal void ThumbZProc()
- {
- if ( gCurrentScrollbar )
- {
- ZScroller* zs = ( ZScroller*) GetControlReference( gCurrentScrollbar );
-
- if ( zs )
- zs->ScrollHandler( gCurrentScrollbar, kControlIndicatorPart );
- }
- }
-
-